home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 6 / develop 6 code / TCP / NewsWatcher / NewsWatcher 2.0d15 source / source / resize.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-27  |  12.2 KB  |  485 lines  |  [TEXT/KAHL]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     resize.c
  4.  
  5.     This module handles window resizing (growing and zooming).
  6.     
  7.     Portions copyright © 1990, Apple Computer.
  8.     Portions copyright © 1993, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <string.h>
  13.  
  14. #include "glob.h"
  15. #include "resize.h"
  16. #include "scroll.h"
  17. #include "util.h"
  18.  
  19.  
  20. /*    SendButtonCont returns a handle to the Send button control for a
  21.     message window. */
  22.  
  23. static ControlHandle SendButtonCont (WindowPtr wind)
  24. {
  25.     ControlHandle theControl;
  26.     
  27.     theControl = ((WindowPeek)wind)->controlList;
  28.     
  29.     while (theControl != nil && GetCRefCon(theControl) != kSendButton) 
  30.         theControl = (**theControl).nextControl;
  31.     return theControl;
  32. }
  33.  
  34.  
  35. /*    RedoControls is called when an article or message window is re-sized 
  36.     and the controls for the window need to be moved/resized.
  37. */
  38.  
  39. static void RedoControls (WindowPtr wind)
  40. {
  41.     TWindow **info;
  42.     EWindowKind kind;
  43.     short panelHeight;
  44.     ControlHandle vScroll, hScroll, sendButton;
  45.     
  46.     info = (TWindow**)GetWRefCon(wind);
  47.     kind = (**info).kind;
  48.     panelHeight = (**info).panelHeight;
  49.  
  50.     vScroll = VScrollCont(wind);
  51.     hScroll = HScrollCont(wind);
  52.     
  53.     HideControl(vScroll);
  54.     MoveControl(vScroll,
  55.         wind->portRect.right - 15,
  56.         wind->portRect.top + panelHeight - 1);
  57.     SizeControl(vScroll,
  58.         16,
  59.         wind->portRect.bottom - wind->portRect.top - panelHeight - 13);
  60.     ShowControl(vScroll);
  61.     
  62.     if (hScroll != nil) {
  63.         HideControl(hScroll);
  64.         MoveControl(hScroll,
  65.             wind->portRect.left + kSectionMargin,
  66.             wind->portRect.bottom - 15);
  67.         SizeControl(hScroll,
  68.             wind->portRect.right - wind->portRect.left - kSectionMargin - 14,
  69.             16);
  70.         ShowControl(hScroll);
  71.     }
  72.     
  73.     if (kind == kMailMessage || kind == kPostMessage) {
  74.         sendButton = SendButtonCont(wind);
  75.         MoveControl(sendButton,
  76.             wind->portRect.right - 65,
  77.             wind->portRect.top + ((panelHeight - 24) >> 1));
  78.     }
  79. }
  80.  
  81.  
  82. /*    FixText is called when a textedit window has been re-sized and the text
  83.     needs to be re-flowed.
  84. */
  85.  
  86. static void FixText (WindowPtr wind)
  87. {    
  88.     TWindow **info;
  89.     short controlLine,charPos;
  90.     Rect viewRect;
  91.     short lineHeight;
  92.     TEHandle theTE;
  93.     ControlHandle sBar;
  94.     
  95.     info = (TWindow**)GetWRefCon(wind);
  96.     theTE = (**info).theTE;
  97.     sBar = VScrollCont(wind);
  98.  
  99.     lineHeight = (**theTE).lineHeight;
  100.     viewRect = wind->portRect;
  101.     viewRect.right -= 15;
  102.     viewRect.bottom -= 15;
  103.     viewRect.top += (**info).panelHeight;
  104.     InsetRect(&viewRect, kTextMargin, kTextMargin);
  105.     (**theTE).destRect = viewRect;
  106.     (**theTE).viewRect = viewRect;
  107.     TECalText(theTE);
  108.     controlLine = GetCtlValue(sBar);
  109.     charPos = (**theTE).lineStarts[controlLine];
  110.     AdjustScrollBar(wind);
  111.     ScrollChar(wind, charPos, false);
  112. }
  113.  
  114.  
  115. /*    FixHeight calculates the height of a window after adjusting it to be an
  116.     exact even multiple of cells or text lines.
  117.     
  118.     Entry:    wind = pointer to window.
  119.             height = window height.
  120.             
  121.     Exit:    function result = adjusted height.
  122. */
  123.  
  124. static short FixHeight (WindowPtr wind, short height)
  125. {
  126.     TWindow **info;
  127.     ListHandle theList;
  128.     TEHandle theTE;
  129.     short h, adjust;
  130.     
  131.     info = (TWindow**)GetWRefCon(wind);
  132.     adjust = (**info).panelHeight + 15;
  133.     theList = (**info).theList;
  134.     if (theList != nil) {
  135.          h = (**theList).cellSize.v;
  136.     } else {
  137.         adjust += 2*kTextMargin;
  138.         theTE = (**info).theTE;
  139.         h = (**theTE).lineHeight;
  140.     }
  141.     height = (height - adjust) / h * h + adjust;
  142.     return height;
  143. }
  144.  
  145.  
  146. /*    SizeContents resizes the window's contents, handling all types of windows.
  147.     It also adjusts the window height so that it contains an exact even multiple
  148.     of cells or text lines.
  149.     
  150.     Entry:    wind = pointer to window.
  151. */
  152.  
  153. void SizeContents (WindowPtr wind)
  154. {
  155.     TWindow **info;
  156.     ListHandle theList;
  157.     Point tmpPt;
  158.     short width, height;
  159.     
  160.     info = (TWindow**) GetWRefCon(wind);
  161.     width = wind->portRect.right;
  162.     height = FixHeight(wind, wind->portRect.bottom);
  163.     SizeWindow(wind, width, height, false);
  164.  
  165.     switch ((**info).kind) {
  166.         case kFullGroup:
  167.         case kNewGroup:
  168.         case kUserGroup:
  169.         case kSubject:
  170.             theList = (**info).theList;
  171.             LSize(width-15, height-15, theList);
  172.             SetPt(&tmpPt, width-15, (**theList).cellSize.v);
  173.             LCellSize(tmpPt, theList);
  174.             break;
  175.         case kArticle:
  176.         case kMiscArticle:
  177.         case kPostMessage:
  178.         case kMailMessage:
  179.             RedoControls(wind);
  180.             FixText(wind);
  181.             break;
  182.     }
  183.     InvalRect(&wind->portRect);
  184. }
  185.  
  186.  
  187. /*    CalcZoom Calculates the maximum needed size for the window.
  188. */
  189.  
  190. static Boolean CalcZoom (WindowPtr wind, Rect *zoomRect)
  191. {
  192.     TWindow **info;
  193.     ListHandle theList;
  194.     TEHandle theTE,tmpTE;
  195.     Handle tmpHandle;
  196.     long width,height,tmpWidth;
  197.     Rect finalRect, tmpRect, userRect;
  198.     Cell theCell;
  199.     TGroup **groupArray;
  200.     TSubject **subjectArray;
  201.     char theString[257];
  202.     short strLen;
  203.     short cellData, cellDataLen;
  204.     short numCells;
  205.     char *p, *q, *pEnd;
  206.     Boolean pastHeader;
  207.     short headerWidth, bodyWidth, nominalWidth;
  208.     Handle strings;
  209.     EWindowKind kind;
  210.     
  211.     info = (TWindow**)GetWRefCon(wind);
  212.     kind = (**info).kind;
  213.     finalRect = *zoomRect;
  214.     userRect = wind->portRect;
  215.     LocalToGlobal((Point*)&userRect.top);
  216.     LocalToGlobal((Point*)&userRect.bottom);
  217.     
  218.     switch (kind) {
  219.         case kFullGroup:
  220.         case kNewGroup:
  221.         case kUserGroup:
  222.         case kSubject:
  223.             theList = (**info).theList;
  224.             height = 20L + (long)((**theList).dataBounds.bottom - 
  225.                 (**theList).dataBounds.top) * 
  226.                 (long)(**theList).cellSize.v;
  227.             if (kind == kFullGroup && gPrefs.maxGroupNameWidth != 0) {
  228.                 width = gPrefs.maxGroupNameWidth;
  229.             } else {
  230.                 strings = (**info).strings;
  231.                 if (kind == kSubject) {
  232.                     subjectArray = (**info).subjectArray;
  233.                 } else {
  234.                     groupArray = (**info).groupArray;
  235.                 }
  236.                 numCells = (**theList).dataBounds.bottom;
  237.                 width = 0;
  238.                 theCell.h = 0;
  239.                 for (theCell.v=0; theCell.v < numCells; theCell.v++) {
  240.                     if (!GiveTime()) return false;
  241.                     cellDataLen = 2;
  242.                     LGetCell(&cellData, &cellDataLen, theCell, theList);
  243.                     if (kind == kSubject) {
  244.                         *theString = '√';
  245.                         strcpy(theString+1, 
  246.                             *strings + (*subjectArray)[cellData].subjectOffset);
  247.                     } else {
  248.                         strcpy(theString, 
  249.                             *strings + (*groupArray)[cellData].nameOffset);
  250.                     }
  251.                     strLen = strlen(theString);
  252.                     tmpWidth = TextWidth(theString, 0, strLen);
  253.                     if (tmpWidth > width) width = tmpWidth;
  254.                 }
  255.                 if (kind == kFullGroup) gPrefs.maxGroupNameWidth = width;
  256.             }
  257.             width += 25;
  258.             if (kind == kUserGroup) {
  259.                 width += (**info).groupNameHCoord;
  260.             } else if (kind == kSubject) {
  261.                 width += (**info).subjectHCoord;
  262.             }
  263.             break;
  264.         case kArticle:
  265.         case kMiscArticle:
  266.             theTE = (**info).theTE;
  267.             HLock((Handle)(**theTE).hText);
  268.             p = *(**theTE).hText;
  269.             pastHeader = false;
  270.             pEnd = p + (**theTE).teLength;
  271.             headerWidth = bodyWidth = 0;
  272.             while (p < pEnd) {
  273.                 if (!GiveTime()) {
  274.                     HUnlock((Handle)(**theTE).hText);
  275.                     return false;
  276.                 }
  277.                 for (q = p; q < pEnd && *q != CR; q++);
  278.                 tmpWidth = TextWidth(p, 0, q-p);
  279.                 if (pastHeader) {
  280.                     if (tmpWidth > bodyWidth) bodyWidth = tmpWidth;
  281.                 } else if (q == p+1) {
  282.                     pastHeader = true;
  283.                 } else {
  284.                     if (tmpWidth > headerWidth) headerWidth = tmpWidth;
  285.                 }
  286.                 p = q+1;
  287.             }
  288.             nominalWidth = 80 * CharWidth('W');
  289.             if (bodyWidth <= nominalWidth && headerWidth <= nominalWidth) {
  290.                 width = bodyWidth > headerWidth ? bodyWidth : headerWidth;
  291.             } else {
  292.                 width = nominalWidth;
  293.             }
  294.             HUnlock((Handle)(**theTE).hText);
  295.             width += (2*kTextMargin) + 18;
  296.             if (LinesInText(theTE) > 100) {
  297.                 height = 0x7fff;
  298.             } else {
  299.                 if (width < 200) width = 200;
  300.                 if (finalRect.right-finalRect.left < width) 
  301.                     width = finalRect.right - finalRect.left;
  302.                 tmpRect = wind->portRect;
  303.                 tmpRect.right = tmpRect.left + width - 15 - 2*kTextMargin;
  304.                 SetPort(wind);
  305.                 tmpTE = TENew(&tmpRect,&tmpRect);
  306.                 tmpHandle = (**tmpTE).hText;
  307.                 (**tmpTE).hText = (**theTE).hText;
  308.                 TECalText(tmpTE);
  309.                 height = 15 + 2*kTextMargin + (**info).panelHeight + 
  310.                     LinesInText(tmpTE) * (**tmpTE).lineHeight;
  311.                 (**tmpTE).hText = tmpHandle;
  312.                 TEDispose(tmpTE);
  313.             }
  314.             break;
  315.         case kMailMessage:
  316.         case kPostMessage:
  317.             height = 0x7fff;
  318.             width = 80 * CharWidth('W') + (2*kTextMargin) + 18;
  319.             break;
  320.     }
  321.  
  322.     if (height < kMinWindHeight) height = kMinWindHeight;
  323.     if (width < kMinWindWidth) width = kMinWindWidth;
  324.  
  325.     if ( (finalRect.right-finalRect.left) > width ) {
  326.         finalRect.right = userRect.left+width;
  327.         finalRect.left = userRect.left;
  328.     }
  329.     if ( (finalRect.bottom-finalRect.top) > height ) {
  330.         finalRect.bottom = userRect.top+height;
  331.         finalRect.top = userRect.top;
  332.     }
  333.     if (finalRect.bottom > zoomRect->bottom) {
  334.         OffsetRect(&finalRect,0,-(finalRect.bottom-zoomRect->bottom));
  335.     }
  336.     if (finalRect.right > zoomRect->right) {
  337.         OffsetRect(&finalRect,-(finalRect.right-zoomRect->right),0);
  338.     }
  339.     if (finalRect.top < zoomRect->top) {
  340.         OffsetRect(&finalRect,0,zoomRect->top - finalRect.top);
  341.         if (finalRect.bottom > zoomRect->bottom)
  342.             finalRect.bottom = zoomRect->bottom;
  343.     }
  344.     if (finalRect.left < zoomRect->left) {
  345.         OffsetRect(&finalRect,zoomRect->left - finalRect.left,0);
  346.         if (finalRect.right > zoomRect->right)
  347.             finalRect.right = zoomRect->right;
  348.     }
  349.     finalRect.bottom = finalRect.top + 
  350.         FixHeight(wind, finalRect.bottom - finalRect.top);
  351.     *zoomRect = finalRect;
  352.     return true;
  353. }
  354.  
  355.  
  356. /* DoZoom: Handles zoom-window events -- from Apple Technical Note #??? */
  357.  
  358. Boolean DoZoom (WindowPtr wind, short zoomDir)
  359. {
  360.     Rect windRect, theSect, zoomRect, tmpRect, testRect;
  361.     GDHandle nthDevice,dominantGDevice;
  362.     long sectArea,greatestArea;
  363.     short bias = 18;
  364.     Boolean sectFlag;
  365.     GrafPtr savePort;
  366.     WStateData **stateHndl;
  367.     
  368.     GetPort(&savePort);
  369.     SetPort(wind);
  370.     
  371.     stateHndl = (WStateData **) ((WindowPeek)wind)->dataHandle;
  372.     
  373.     if (zoomDir == inZoomOut) {
  374.         windRect = wind->portRect;
  375.         LocalToGlobal((Point*)&windRect.top);
  376.         LocalToGlobal((Point*)&windRect.bottom);
  377.         if (gHasColorQD) {
  378.             testRect = windRect;
  379.             testRect.top -= bias;
  380.             nthDevice = GetDeviceList();
  381.             dominantGDevice = 0;
  382.             greatestArea = 0;
  383.             while (nthDevice != nil) {
  384.                 if (TestDeviceAttribute(nthDevice,screenDevice) &&
  385.                     TestDeviceAttribute(nthDevice,screenActive)) {
  386.                         sectFlag = SectRect(&testRect,&((**nthDevice).gdRect),&theSect);
  387.                         sectArea = (long)(theSect.right - theSect.left) * 
  388.                             (long)(theSect.bottom - theSect.top);
  389.                         if (sectArea > greatestArea) {
  390.                             greatestArea = sectArea;
  391.                             dominantGDevice = nthDevice;
  392.                         }
  393.                 }
  394.                 nthDevice = GetNextDevice(nthDevice);
  395.             }
  396.             
  397.             if (dominantGDevice == GetMainDevice())
  398.                 bias += GetMBarHeight();
  399.             
  400.             if (dominantGDevice)
  401.                 tmpRect = (**dominantGDevice).gdRect;
  402.             else
  403.                 tmpRect = gDesktopExtent;
  404.             
  405.             zoomRect = tmpRect;
  406.             zoomRect.top += bias;
  407.             InsetRect(&zoomRect, 4, 4);
  408.         } else {
  409.             zoomRect = qd.screenBits.bounds;
  410.             zoomRect.top += GetMBarHeight() + bias;
  411.             InsetRect(&zoomRect, 4, 4);
  412.         }
  413.         if (!CalcZoom(wind, &zoomRect)) {
  414.             SetPort(savePort);
  415.             return false;
  416.         }
  417.         if (EqualRect(&windRect, &zoomRect)) {
  418.             SetPort(savePort);
  419.             return true;
  420.         }
  421.         (**stateHndl).stdState = zoomRect;
  422.     }
  423.     
  424.     
  425.     EraseRect(&wind->portRect);
  426.     ZoomWindow(wind,zoomDir,false);
  427.  
  428.     InvalRect(&wind->portRect);
  429.     SizeContents(wind);
  430.     SetRect(&tmpRect,wind->portRect.left,wind->portRect.bottom-16,
  431.                 wind->portRect.right,wind->portRect.bottom);
  432.     InvalRect(&tmpRect);
  433.     
  434.     SetPort(savePort);
  435.     return true;
  436. }
  437.  
  438.  
  439. /* DoGrow handles grow window events */
  440.  
  441. void DoGrow (WindowPtr wind, Point globMouse)
  442. {
  443.     long newSize;
  444.     Rect tmpRect;
  445.     GrafPtr    savePort;
  446.     WStateData **stateHndl;
  447.     
  448.     if ((newSize = GrowWindow(wind,globMouse,&gWindLimits)) != 0) {
  449.         GetPort(&savePort);
  450.         SetPort(wind);
  451.         SetRect(&tmpRect,wind->portRect.right-15-kTextMargin,
  452.             wind->portRect.top,
  453.             wind->portRect.right,
  454.             wind->portRect.bottom);
  455.         InvalRect(&tmpRect);
  456.         SetRect(&tmpRect,wind->portRect.left,
  457.             wind->portRect.bottom-15-kTextMargin,
  458.             wind->portRect.right-16,
  459.             wind->portRect.bottom);
  460.         InvalRect(&tmpRect);
  461.         
  462.         SizeWindow(wind, LoWord(newSize), HiWord(newSize), true);
  463.         SizeContents(wind);
  464.         
  465.         SetRect(&tmpRect,wind->portRect.right-15,
  466.             wind->portRect.top,
  467.             wind->portRect.right,
  468.             wind->portRect.bottom);
  469.         InvalRect(&tmpRect);
  470.         SetRect(&tmpRect,wind->portRect.left,
  471.             wind->portRect.bottom-15,
  472.             wind->portRect.right-15,
  473.             wind->portRect.bottom);
  474.         InvalRect(&tmpRect);
  475.         
  476.         stateHndl = (WStateData**)((WindowPeek)wind)->dataHandle;
  477.         tmpRect = wind->portRect;
  478.         LocalToGlobal((Point*)&tmpRect.top);
  479.         LocalToGlobal((Point*)&tmpRect.bottom);
  480.         (**stateHndl).userState = tmpRect;
  481.         
  482.         SetPort(savePort);
  483.     }
  484. }
  485.